﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Atendex.Containex;
using Atendex.Dominio.Interfaces;
using Atendex.Infraestrutura.Repositórios;
using Atendex.Web.AppCode;

namespace Atendex.Web
{
    public partial class CadastrarTipoSolicitante : System.Web.UI.Page
    {
        private Dictionary<int, ITipoSolicitacao> tipoSolicitacaoCache;

        protected void Page_Load(object sender, EventArgs e)
        {
            IGerente gerente = AtendexContext.GerenteAtual(this);
            if (gerente == null)
            {
                pnlCadastro.Visible = false;
                lblMessage.Text = "Você deve fazer o login como gerente antes de cadastrar um Tipo de Solicitação.";
                lblMessage.Visible = true;
                return;
            }


            if (!Page.IsPostBack)
            {
                pnlCadastro.Visible = true;
                CarregaTipoSolicitacoes();
            }
            else
            {
                lblMessage.Visible = false;
            }
            CarregarGridTiposSolicitantes();
        }

        private bool Editando
        {
            get
            {
                bool? editando = (bool?)ViewState["editando"];
                if (editando == null || editando == false)
                    return false;
                return true;
            }
            set
            {
                ViewState["editando"] = value;
                if (value)
                {
                    btnLimpar.Text = "Cancelar";
                    btnExcluir.Visible = true;
                }
                else
                {
                    btnLimpar.Text = "Limpar";
                    btnExcluir.Visible = false;
                }
            }
        }

        private ITipoSolicitante ObjetoEditado
        {
            get
            {
                return (ITipoSolicitante)ViewState["objeto_editado"];
            }
            set
            {
                ViewState["objeto_editado"] = value;
            }
        }

        private void CarregarGridTiposSolicitantes()
        {
            var repositorio = new RepositorioTipoSolicitante();
            var tiposSolicitantes = repositorio.ObtemTodos();
            gvTiposSolicitantes.DataSource = tiposSolicitantes;
            gvTiposSolicitantes.DataBind();
            ViewState["tipos"] = tiposSolicitantes;
        }

        private void CarregarObjeto(ITipoSolicitante tipoSolicitante)
        {
            ObjetoEditado = tipoSolicitante;
            Editando = true;

            txtNome.Text = tipoSolicitante.Nome;

            IList<string> tiposSolicitacaoIds = new List<string>();
            foreach (ITipoSolicitacao tipoSolicitacao in tipoSolicitante.SolicitacoesPermitidas)
            {
                tiposSolicitacaoIds.Add(tipoSolicitacao.Id.ToString());
            }

            ListBoxHelper.TransfereItemsDeLista(lstTiposSolicitacoesDisponiveis,
                lstTiposSolicitacoesEscolhidos, tiposSolicitacaoIds);
            UpdateListTransferButtons();
        }

        private Dictionary<int, ITipoSolicitacao> SolicitacoesCache
        {
            get
            {
                tipoSolicitacaoCache = Session["TipoSolicitacoesCache"] as Dictionary<int, ITipoSolicitacao>;
                if (tipoSolicitacaoCache == null)
                {
                    tipoSolicitacaoCache = new Dictionary<int, ITipoSolicitacao>();
                    Session["TipoSolicitacoesCache"] = tipoSolicitacaoCache;
                }
                return tipoSolicitacaoCache;
            }
        }

        private void CarregaTipoSolicitacoes()
        {
            var repositorioSolicitacaoAN = new RepositorioTipoSolicitacaoAN();
            var repositorioSolicitacaoCurso = new RepositorioTipoSolicitacaoCurso();

            var tiposSolicitacoesAN = repositorioSolicitacaoAN.ObtemTodos();
            var tiposSolicitacoesCurso = repositorioSolicitacaoCurso.ObtemTodos();

            var cache = SolicitacoesCache;
            foreach (var solicitacao in tiposSolicitacoesAN)
            {
                if (cache.ContainsKey(solicitacao.Id))
                {
                    cache[solicitacao.Id] = solicitacao;
                }
                else
                {
                    cache.Add(solicitacao.Id, solicitacao);
                }

                lstTiposSolicitacoesDisponiveis.Items.Add(
                    new ListItem("[Area] " + solicitacao.Nome, solicitacao.Id.ToString()));
            }

            foreach (var solicitacao in tiposSolicitacoesCurso)
            {
                if (cache.ContainsKey(solicitacao.Id))
                {
                    cache[solicitacao.Id] = solicitacao;
                }
                else
                {
                    cache.Add(solicitacao.Id, solicitacao);
                }

                lstTiposSolicitacoesDisponiveis.Items.Add(
                    new ListItem("[Curso] " + solicitacao.Nome, solicitacao.Id.ToString()));
            }
        }

        protected void btnAddTipoSolicitacao_Click(object sender, EventArgs e)
        {
            ListBoxHelper.TransfereListItems(lstTiposSolicitacoesDisponiveis, lstTiposSolicitacoesEscolhidos);
            UpdateListTransferButtons();
        }

        protected void btnRemoveTipoSolicitcao_Click(object sender, EventArgs e)
        {
            ListBoxHelper.TransfereListItems(lstTiposSolicitacoesEscolhidos, lstTiposSolicitacoesDisponiveis);
            UpdateListTransferButtons();
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            try
            {
                if (Editando)
                    AtualizarTipoSolicitante();
                else
                    SalvarTipoSolicitante();

                if (Editando)
                {
                    lblMessage.Text = "Atualização realizada com sucesso.";
                    Editando = false;
                }
                else
                {
                    lblMessage.Text = "Cadastro com sucesso.";
                }

                LimpaCampos();
                CarregarGridTiposSolicitantes();                
            }
            catch (Exception ex)
            {
                lblMessage.Text = ex.Message;
            }
            finally
            {
                lblMessage.Visible = true;
            }
        }

        private void SalvarTipoSolicitante()
        {
            ITipoSolicitante tipoSolicitante = Container.CriarTipoSolicitante(txtNome.Text);
            new RepositorioTipoSolicitante().Salvar(tipoSolicitante);

            var repositorioSolicitacaoAN = new RepositorioTipoSolicitacaoAN();
            var repositorioSolicitacaoCurso = new RepositorioTipoSolicitacaoCurso();

            Dictionary<int, ITipoSolicitacao> cache = SolicitacoesCache;
            foreach (ListItem item in lstTiposSolicitacoesEscolhidos.Items)
            {
                int tipoSolicitacaoId = int.Parse(item.Value);
                ITipoSolicitacao tipoSolicitacao = cache[tipoSolicitacaoId];

                tipoSolicitacao.SolicitantesPermitidos.Add(tipoSolicitante);

                if (tipoSolicitacao is ITipoSolicitacaoAN)
                    repositorioSolicitacaoAN.Salvar(tipoSolicitacao as ITipoSolicitacaoAN);
                else if (tipoSolicitacao is ITipoSolicitacaoCurso)
                    repositorioSolicitacaoCurso.Salvar(tipoSolicitacao as ITipoSolicitacaoCurso);
            }
        }

        private void AtualizarTipoSolicitante()
        {
            ITipoSolicitante tipoSolicitante = ObjetoEditado;
            tipoSolicitante.Nome = txtNome.Text;

            new RepositorioTipoSolicitante().Salvar(tipoSolicitante);

            var repositorioSolicitacaoAN = new RepositorioTipoSolicitacaoAN();
            var repositorioSolicitacaoCurso = new RepositorioTipoSolicitacaoCurso();

            var tiposSolicitacaoIds = new List<int>();
            foreach (ListItem item in lstTiposSolicitacoesEscolhidos.Items)
            {
                tiposSolicitacaoIds.Add(int.Parse(item.Value));
            }

            foreach (ITipoSolicitacao tipoSolicitacao in tipoSolicitante.SolicitacoesPermitidas)
            {
                if (!tiposSolicitacaoIds.Contains(tipoSolicitacao.Id))
                {
                    // remove tipo de solicitacao
                    foreach (ITipoSolicitante solicitante in tipoSolicitacao.SolicitantesPermitidos)
                    {
                        if (solicitante.Id != tipoSolicitante.Id) continue;

                        tipoSolicitacao.SolicitantesPermitidos.Remove(solicitante);
                        break;
                    }
                    if (tipoSolicitacao is ITipoSolicitacaoAN)
                    {
                        repositorioSolicitacaoAN.Salvar(tipoSolicitacao as ITipoSolicitacaoAN);
                    }
                    else if (tipoSolicitacao is ITipoSolicitacaoCurso)
                    {
                        repositorioSolicitacaoCurso.Salvar(tipoSolicitacao as ITipoSolicitacaoCurso);
                    }
                    else
                    {
                        continue;
                    }
                }
                else
                {
                    tiposSolicitacaoIds.Remove(tipoSolicitacao.Id);
                }
            }

            // os que sobraram sao novos
            foreach (int id in tiposSolicitacaoIds)
            {
                var novoTipo = SolicitacoesCache[id];
                novoTipo.SolicitantesPermitidos.Add(tipoSolicitante);

                if (novoTipo is ITipoSolicitacaoAN)
                    repositorioSolicitacaoAN.Salvar(novoTipo as ITipoSolicitacaoAN);
                else if (novoTipo is ITipoSolicitacaoCurso)
                    repositorioSolicitacaoCurso.Salvar(novoTipo as ITipoSolicitacaoCurso);
            }
        }

        private void UpdateListTransferButtons()
        {
            btnAddTipoSolicitacao.Enabled =
                lstTiposSolicitacoesDisponiveis.Items.Count > 0;
            btnRemoveTipoSolicitcao.Enabled =
                lstTiposSolicitacoesEscolhidos.Items.Count > 0;
        }

        protected void btnLimpar_Click(object sender, EventArgs e)
        {
            LimpaCampos();
            Editando = false;
        }

        private void LimpaCampos()
        {
            txtNome.Text = string.Empty;
            ListBoxHelper.TransfereTudo(lstTiposSolicitacoesEscolhidos, lstTiposSolicitacoesDisponiveis);
            UpdateListTransferButtons();
        }

        protected void btnExcluir_Click(object sender, EventArgs e)
        {
            try
            {
                ITipoSolicitante tipoSolicitante = ObjetoEditado;
                tipoSolicitante.Ativo = false;
                new RepositorioTipoSolicitante().Salvar(tipoSolicitante);
                lblMessage.Text = "O tipo de solicitante foi excluído.";
                LimpaCampos();
                Editando = false;
                CarregarGridTiposSolicitantes();
            }
            catch (RepositorioException)
            {
                lblMessage.Text = "Não foi possível excluir o tipo.";
            }
            finally
            {
                lblMessage.Visible = true;
            }
        }

        protected void gvTiposSolicitantes_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            // commandargument parece vir sempre com o índice da linha que teve
            // o botão apertado
            int i = int.Parse((string)e.CommandArgument);
            ITipoSolicitante tipo = ((ITipoSolicitante[])ViewState["tipos"])[i];
            CarregarObjeto(tipo);
        }
    }
}
